﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Text;
using UnityEngine;

namespace KerbinCity
{
    public class BlockGenerator
    {
        public static Material CityLightsTexture { get { return cityLightsTexture; } }
        private static Material cityLightsTexture;
        private static Material baseTexture;
        const int BlOCK_WIDTH = 4;
        const int BLOCK_DEPTH = 4;
        static System.Random random = new System.Random();

        private class ConnPoint
        {
            public bool IsConnected;

            public void Random()
            {
                this.IsConnected = (random.NextDouble() < 0.25);
            }
        }

        private class ConnectionSet
        {
            public ConnPoint Top;
            public ConnPoint Bottom;
            public ConnPoint Left;
            public ConnPoint Right;

            public ConnectionSet()
            {
                Top = new ConnPoint();
                Bottom = new ConnPoint();
                Left = new ConnPoint();
                Right = new ConnPoint();
            }

            public ConnectionSet(ConnectionSet connectionSet, int side)
                : this()
            {
                if (side == 0)
                {
                    this.Bottom = connectionSet.Top;
                }
                else
                {
                    this.Left = connectionSet.Right;
                }
            }

            public ConnectionSet(ConnectionSet connectionSet1, ConnectionSet connectionSet2)
                : this()
            {
                this.Left = connectionSet1.Right;
                this.Bottom = connectionSet2.Top;
            }

            public static ConnectionSet[,] GenerateBlock(int width, int depth)
            {
                ConnectionSet[,] set = new ConnectionSet[width - 1, depth - 1];

                for (int y = 0; y < set.GetLength(1); y++)
                {
                    for (int x = 0; x < set.GetLength(0); x++)
                    {
                        if (x == 0 && y == 0)
                        {
                            set[x, y] = new ConnectionSet();
                        }
                        else if (x == 0)
                        {
                            set[x, y] = new ConnectionSet(set[x, y - 1], 0);
                        }
                        else if (y == 0)
                        {
                            set[x, y] = new ConnectionSet(set[x - 1, y], 1);
                        }
                        else
                        {
                            set[x, y] = new ConnectionSet(set[x - 1, y], set[x, y - 1]);
                        }
                        set[x, y].Top.Random();
                        set[x, y].Bottom.Random();
                        set[x, y].Left.Random();
                        set[x, y].Right.Random();
                    }

                }

                FixLs(set);
                ExposeCenter(set);
                FixLs(set);

                KerbinCity.Log(GetString(set));
                Console.WriteLine(GetString(set));
                return set;
            }

            private static void ExposeCenter(ConnectionSet[,] set)
            {
                int width = set.GetLength(0);
                int depth = set.GetLength(1);
                for (int x = 1; x <= (width / 2); x++)
                {
                    for (int y = 1; y <= (depth / 2); y++)
                    {
                        switch (set[x, y].GetCount())
                        {
                            case 0:
                                Expose(set[x - 1, y - 1].Top, set[x - 1, y - 1].Right);
                                Expose(set[x - 1, y + 1].Bottom, set[x - 1, y + 1].Right);
                                Expose(set[x + 1, y - 1].Top, set[x + 1, y - 1].Left);
                                Expose(set[x + 1, y + 1].Bottom, set[x + 1, y + 1].Left);
                                break;
                            case 1:
                                ExposeTri(set, x, y);
                                break;
                            case 2:
                                ExposeBi(set, x, y);
                                break;
                            case 4:
                                Expose(set, x, y);
                                break;
                        }
                    }
                }

            }

            private static void ExposeTri(ConnectionSet[,] set, int x, int y)
            {
                //the divide is horizontal... -|-
                if (set[x, y].Top.IsConnected)
                {

                    Expose(set[x - 1, y - 1].Top, set[x - 1, y - 1].Right);
                    Expose(set[x + 1, y - 1].Top, set[x + 1, y - 1].Left);

                    if (
                        !(set[x - 1, y + 1].Bottom.IsConnected && set[x - 1, y + 1].Right.IsConnected &&
                        set[x + 1, y + 1].Bottom.IsConnected && set[x + 1, y + 1].Left.IsConnected))
                    {
                        switch (random.Next(0, 2))
                        {
                            case 0:
                                Expose(set[x - 1, y + 1].Bottom, set[x - 1, y + 1].Right);
                                break;
                            case 1:
                                Expose(set[x + 1, y + 1].Bottom, set[x + 1, y + 1].Left);
                                break;
                        }
                    }

                }
                else if (set[x, y].Bottom.IsConnected)// _|_
                {
                    //expose top left and right
                    Expose(set[x - 1, y + 1].Bottom, set[x - 1, y + 1].Right);
                    Expose(set[x + 1, y + 1].Bottom, set[x + 1, y + 1].Left);
                    //expose bottom
                    if (
                        !(set[x - 1, y - 1].Top.IsConnected && set[x - 1, y - 1].Right.IsConnected &&
                        set[x + 1, y - 1].Top.IsConnected && set[x + 1, y - 1].Left.IsConnected))
                    {
                        switch (random.Next(0, 2))
                        {
                            case 0:
                                Expose(set[x - 1, y - 1].Top, set[x - 1, y - 1].Right);
                                break;
                            case 1:
                                Expose(set[x + 1, y - 1].Top, set[x + 1, y - 1].Left);
                                break;
                        }
                    }
                }
                else if (set[x, y].Left.IsConnected)// |-
                {
                    Expose(set[x + 1, y + 1].Bottom, set[x + 1, y + 1].Left);
                    Expose(set[x + 1, y - 1].Top, set[x + 1, y - 1].Left);

                    if (
                        !(set[x - 1, y + 1].Bottom.IsConnected && set[x - 1, y + 1].Right.IsConnected &&
                        set[x + 1, y + 1].Bottom.IsConnected && set[x + 1, y + 1].Left.IsConnected))
                    {
                        switch (random.Next(0, 2))
                        {
                            case 0:
                                Expose(set[x - 1, y + 1].Bottom, set[x - 1, y + 1].Right);
                                break;
                            case 1:
                                Expose(set[x - 1, y - 1].Top, set[x - 1, y - 1].Right);
                                break;
                        }
                    }

                }
                else if (set[x, y].Right.IsConnected)// -|
                {
                    Expose(set[x - 1, y + 1].Bottom, set[x - 1, y + 1].Right);
                    Expose(set[x - 1, y - 1].Top, set[x - 1, y - 1].Right);

                    if (
                        !(set[x + 1, y + 1].Bottom.IsConnected && set[x + 1, y + 1].Left.IsConnected &&
                        set[x + 1, y - 1].Top.IsConnected && set[x + 1, y - 1].Left.IsConnected))
                    {
                        switch (random.Next(0, 2))
                        {
                            case 0:
                                Expose(set[x + 1, y + 1].Bottom, set[x + 1, y + 1].Left);
                                break;
                            case 1:
                                Expose(set[x + 1, y - 1].Top, set[x + 1, y - 1].Left);
                                break;
                        }
                    }
                }
            }

            private static void ExposeBi(ConnectionSet[,] set, int x, int y)
            {
                //the divide is horizontal...
                if (set[x, y].Top.IsConnected)
                {
                    if (
                        !(set[x - 1, y + 1].Bottom.IsConnected && set[x - 1, y + 1].Right.IsConnected &&
                        set[x + 1, y + 1].Bottom.IsConnected && set[x + 1, y + 1].Left.IsConnected))
                    {
                        switch (random.Next(0, 2))
                        {
                            case 0:
                                Expose(set[x - 1, y + 1].Bottom, set[x - 1, y + 1].Right);
                                break;
                            case 1:
                                Expose(set[x + 1, y + 1].Bottom, set[x + 1, y + 1].Left);
                                break;
                        }
                    }
                    if (
                        !(set[x - 1, y - 1].Top.IsConnected && set[x - 1, y - 1].Right.IsConnected &&
                        set[x + 1, y - 1].Top.IsConnected && set[x + 1, y - 1].Left.IsConnected))
                    {
                        switch (random.Next(0, 2))
                        {
                            case 0:
                                Expose(set[x - 1, y - 1].Top, set[x - 1, y - 1].Right);
                                break;
                            case 1:
                                Expose(set[x + 1, y - 1].Top, set[x + 1, y - 1].Left);
                                break;
                        }
                    }
                }
                else // vertical divide
                {
                    if (
                        !(set[x - 1, y + 1].Bottom.IsConnected && set[x - 1, y + 1].Right.IsConnected &&
                        set[x + 1, y + 1].Bottom.IsConnected && set[x + 1, y + 1].Left.IsConnected))
                    {
                        switch (random.Next(0, 2))
                        {
                            case 0:
                                Expose(set[x - 1, y + 1].Bottom, set[x - 1, y + 1].Right);
                                break;
                            case 1:
                                Expose(set[x - 1, y - 1].Top, set[x - 1, y - 1].Right);
                                break;
                        }
                    }
                    if (
                        !(set[x + 1, y + 1].Bottom.IsConnected && set[x + 1, y + 1].Left.IsConnected &&
                        set[x + 1, y - 1].Top.IsConnected && set[x + 1, y - 1].Left.IsConnected))
                    {
                        switch (random.Next(0, 2))
                        {
                            case 0:
                                Expose(set[x + 1, y + 1].Bottom, set[x + 1, y + 1].Left);
                                break;
                            case 1:
                                Expose(set[x + 1, y - 1].Top, set[x + 1, y - 1].Left);
                                break;
                        }
                    }
                }
            }

            private static void Expose(ConnectionSet[,] set, int x, int y)
            {
                if (!(set[x - 1, y - 1].Top.IsConnected && set[x - 1, y - 1].Right.IsConnected &&
                    set[x - 1, y + 1].Bottom.IsConnected && set[x - 1, y + 1].Right.IsConnected &&
                    set[x + 1, y - 1].Top.IsConnected && set[x + 1, y - 1].Left.IsConnected &&
                    set[x + 1, y + 1].Bottom.IsConnected && set[x + 1, y + 1].Left.IsConnected))
                {
                    switch (random.Next(0, 4))
                    {
                        case 0:
                            Expose(set[x - 1, y - 1].Top, set[x - 1, y - 1].Right);
                            break;
                        case 1:
                            Expose(set[x - 1, y + 1].Bottom, set[x - 1, y + 1].Right);
                            break;
                        case 2:
                            Expose(set[x + 1, y - 1].Top, set[x + 1, y - 1].Left);
                            break;
                        case 3:
                            Expose(set[x + 1, y + 1].Bottom, set[x + 1, y + 1].Left);
                            break;
                    }
                }
            }

            private static void Expose(ConnPoint connPoint1, ConnPoint connPoint2)
            {
                if (!connPoint1.IsConnected && !connPoint2.IsConnected)
                {
                    if (random.Next(0, 2) == 0)
                    {
                        connPoint1.IsConnected = true;
                    }
                    else
                    {
                        connPoint2.IsConnected = true;
                    }
                }
            }

            private static void RecurseFix(ConnectionSet[,] set, int x, int y)
            {
                if (set[x, y].FixLs())
                {
                    if (x > 0)
                    {
                        RecurseFix(set, x - 1, y);
                    }
                    if (y > 0)
                    {
                        RecurseFix(set, x, y - 1);
                    }
                    if (x + 1 < set.GetLength(0))
                    {
                        RecurseFix(set, x + 1, y);
                    }
                    if (y + 1 < set.GetLength(1))
                    {
                        RecurseFix(set, x, y + 1);
                    }
                }
            }

            private static void FixLs(ConnectionSet[,] set)
            {

                for (int y = 0; y < set.GetLength(1); y++)
                {
                    for (int x = 0; x < set.GetLength(0); x++)
                    {
                        RecurseFix(set, x, y);
                    }
                }

            }

            private bool FixLs()
            {
                if (CreatesCorner() || NonsensicalDevision())
                {
                    this.Top.IsConnected = true;
                    this.Bottom.IsConnected = true;
                    this.Left.IsConnected = true;
                    this.Right.IsConnected = true;
                    return true;
                }
                return false;
            }

            private int GetCount()
            {
                int count = 0;
                if (this.Top.IsConnected)
                {
                    count++;
                }
                if (this.Bottom.IsConnected)
                {
                    count++;
                }
                if (this.Left.IsConnected)
                {
                    count++;
                }
                if (this.Right.IsConnected)
                {
                    count++;
                }
                return count;
            }

            private bool NonsensicalDevision()
            {
                int count = GetCount();
                if (count == 3)
                {
                    return true;
                }
                return false;
            }

            private bool CreatesCorner()
            {
                if (this.Top.IsConnected && this.Left.IsConnected && !(this.Bottom.IsConnected || this.Right.IsConnected))
                {
                    return true;
                }
                if (this.Bottom.IsConnected && this.Left.IsConnected && !(this.Top.IsConnected || this.Right.IsConnected))
                {
                    return true;
                }
                if (this.Top.IsConnected && this.Right.IsConnected && !(this.Bottom.IsConnected || this.Left.IsConnected))
                {
                    return true;
                }
                if (this.Bottom.IsConnected && this.Right.IsConnected && !(this.Top.IsConnected || this.Left.IsConnected))
                {
                    return true;
                }
                return false;
            }

            public static String GetString(ConnectionSet[,] set)
            {
                String ret = "";
                string bottom = "|";
                for (int y = set.GetLength(1) - 1; y >= 0; y--)
                {
                    ret += "|";

                    for (int x = 0; x < set.GetLength(0); x++)
                    {

                        if (x == 0 && !set[x, y].Left.IsConnected)
                        {
                            ret += "_";
                        }
                        else if (x == 0)
                        {
                            ret += " ";
                        }
                        if (!set[x, y].Top.IsConnected)
                        {
                            ret += "|";
                        }
                        else
                        {
                            ret += " ";
                        }
                        if (!set[x, y].Right.IsConnected)
                        {
                            ret += "_";
                        }
                        else
                        {
                            ret += " ";
                        }
                        if (y == 0 && !set[x, y].Bottom.IsConnected)
                        {
                            bottom += " |";
                        }
                        else if (y == 0)
                        {
                            bottom += "  ";
                        }

                    }
                    ret += "|\r\n";
                }
                return ret + bottom + " |";
            }
        }

        private static void SetBlocks(Vector2[,,] blockSize)
        {
            float xRemaining = 1.0f;
            float yRemaining = 1.0f;

            float xmin = 1.0f / (float)(blockSize.GetLength(0)+1);
            float ymin = 1.0f / (float)(blockSize.GetLength(1)+1);
            float xstd = 1.0f / (float)(blockSize.GetLength(0) - 1);
            float ystd = 1.0f / (float)(blockSize.GetLength(1) - 1);

            for (int x = 0; x < blockSize.GetLength(0); x++)
            {
                for (int y = 0; y < blockSize.GetLength(1); y++)
                {
                    blockSize[x, y, 0] = new Vector2();
                }
            }

            for (int x = 0, xLeft = blockSize.GetLength(0); x < blockSize.GetLength(0); x++, xLeft--)
            {
                float xmax = Math.Min((xRemaining - (xmin * (float)(xLeft))), xstd - xmin);
                float widthp = xmin + (float)(random.NextDouble() * xmax);
                xRemaining -= widthp;
                blockSize[x, 0, 0].x = widthp;
            }
            for (int y = 0, yleft = blockSize.GetLength(0); y < blockSize.GetLength(0); y++, yleft--)
            {
                float ymax = Math.Min((yRemaining - (ymin * (float)(yleft))), ystd - ymin);
                float depthp = ymin + (float)(random.NextDouble() * ymax);
                yRemaining -= depthp;
                blockSize[0, y, 0].y = depthp;
            }
            for (int x = 0; x < blockSize.GetLength(0); x++)
            {
                for (int y = 0; y < blockSize.GetLength(1); y++)
                {
                    blockSize[x,y,0].x = blockSize[x,0,0].x;
                    blockSize[x,y,0].y = blockSize[0,y,0].y;
                }
            }
            
        }

        private static void SetPlaces(Vector2[, ,] blockSize)
        {
            float width = 0.0f;
            float depth = 0.0f;

            for (int x = 0; x < blockSize.GetLength(0); x++)
            {
                width += blockSize[x, 0, 0].x;
            }
            for (int y = 0; y < blockSize.GetLength(1); y++)
            {
                depth += blockSize[0, y, 0].y;
            }
            Console.WriteLine("width: " + width);
            Console.WriteLine("depth: " + depth);

            float leftoverWidth = 1.0f - width;
            float leftoverDepth = 1.0f - depth;

            float widthSeperation = leftoverWidth / (float)(blockSize.GetLength(0) + 1);
            float depthSeperation = leftoverDepth / (float)(blockSize.GetLength(1) + 1);

            float accWidth = widthSeperation;
            float accDepth = depthSeperation;

            for (int x = 0; x < blockSize.GetLength(0); x++)
            {
                for (int y = 0; y < blockSize.GetLength(1); y++)
                {
                    blockSize[x, y, 1] = new Vector2();
                }
            }

            for (int x = 0; x < blockSize.GetLength(0); x++)
            {
                for (int y = 0; y < blockSize.GetLength(1); y++)
                {
                    blockSize[x, y, 1].x = accWidth;
                }
                accWidth += blockSize[x, 0, 0].x + widthSeperation;
            }

            for (int y = 0; y < blockSize.GetLength(1); y++)
            {
                for (int x = 0; x < blockSize.GetLength(0); x++)
                {
                    blockSize[x, y, 1].y = accDepth;
                }
                accDepth += blockSize[0, y, 0].y + depthSeperation;
            }

        }

        private static void ApplyDimensions(Vector2[, ,] footprints, float width, float depth)
        {
            for (int x = 0; x < footprints.GetLength(0); x++)
            {
                for (int y = 0; y < footprints.GetLength(1); y++)
                {
                    footprints[x, y, 0].x *= width;
                    footprints[x, y, 0].y *= depth;
                    footprints[x, y, 1].x *= width;
                    footprints[x, y, 1].y *= depth;
                }
            }
        }

        private static void MergeBlocks(Vector2[, ,] footprints, ConnectionSet[,] ConBlockSet)
        {
            for (int x = 0; x < ConBlockSet.GetLength(0); x++)
            {
                for (int y = 0; y < ConBlockSet.GetLength(1); y++)
                {
                    if (ConBlockSet[x, y].Bottom.IsConnected)
                    {
                        footprints[x + 1, y, 0].x = footprints[x, y, 0].x + footprints[x + 1, y, 0].x;
                        footprints[x + 1, y, 1].x = footprints[x, y, 1].x + (((footprints[x + 1, y, 1].x - footprints[x, y, 1].x) - footprints[x, y, 0].x) / 2.0f);
                    }
                    if (ConBlockSet[x, y].Left.IsConnected)
                    {
                        footprints[x, y + 1, 0].y = footprints[x, y, 0].y + footprints[x, y + 1, 0].y;
                        footprints[x, y + 1, 1].y = footprints[x, y, 1].y + (((footprints[x, y + 1, 1].y - footprints[x, y, 1].y) - footprints[x, y, 0].y) / 2.0f);
                    }
                    if (x == (ConBlockSet.GetLength(1) - 1) && ConBlockSet[x, y].Right.IsConnected)
                    {
                        footprints[x + 1, y + 1, 0].y = footprints[x + 1, y, 0].y + footprints[x + 1, y + 1, 0].y;
                        footprints[x + 1, y + 1, 1].y = footprints[x + 1, y, 1].y + (((footprints[x + 1, y + 1, 1].y - footprints[x + 1, y, 1].y) - footprints[x + 1, y, 0].y) / 2.0f);
                    }
                    if (y == (ConBlockSet.GetLength(0) - 1) && ConBlockSet[x, y].Top.IsConnected)
                    {
                        footprints[x + 1, y + 1, 0].x = footprints[x, y + 1, 0].x + footprints[x + 1, y + 1, 0].x;
                        footprints[x + 1, y + 1, 1].x = footprints[x, y + 1, 1].x + (((footprints[x + 1, y + 1, 1].x - footprints[x, y + 1, 1].x) - footprints[x, y + 1, 0].x) / 2.0f);
                    }

                    if (ConBlockSet[x, y].Bottom.IsConnected || ConBlockSet[x, y].Left.IsConnected)
                    {
                        footprints[x, y, 0] = new Vector2(0,0);
                    }
                    if (x == (ConBlockSet.GetLength(1) - 1) && ConBlockSet[x, y].Right.IsConnected)
                    {
                        footprints[x + 1, y, 0] = new Vector2(0, 0);
                    }
                    if (y == (ConBlockSet.GetLength(0) - 1) && ConBlockSet[x, y].Top.IsConnected)
                    {
                        footprints[x, y + 1, 0] = new Vector2(0, 0);
                    }

                }
            }
        }

        public static Vector2[,,] GenerateBuildingFootprints(float width, float depth)
        {
            
            Vector2[,,] footprints = new Vector2[BlOCK_WIDTH,BLOCK_DEPTH,2];
            ConnectionSet[,] ConBlockSet = ConnectionSet.GenerateBlock(BlOCK_WIDTH, BLOCK_DEPTH);

            SetBlocks(footprints);
            SetPlaces(footprints);
            ApplyDimensions(footprints, width, depth);
            MergeBlocks(footprints, ConBlockSet);

            return footprints;
        }

        public static void InitTextures()
        {
            Assembly assembly = Assembly.GetExecutingAssembly();
            StreamReader shaderStreamReader = new StreamReader(assembly.GetManifestResourceStream("KerbinCity.compiledShader.txt"));

            cityLightsTexture = new Material(shaderStreamReader.ReadToEnd());

            baseTexture = new Material(Shader.Find("VertexLit"));
            baseTexture.mainTexture = GameDatabase.Instance.GetTexture("Redev/Textures/other/base", false);
            baseTexture.mainTextureScale = new Vector2(100f, 100f);
            //cityLightsTexture.mainTexture = GameDatabase.Instance.GetTexture("Redev/Textures/tops/light", false);
            //cityLightsTexture.mainTextureScale = new Vector2(100f, 100f);
        }

        public static GameObject Generate(float width, float depth)
        {
            GameObject generatedBuilding = new GameObject("KerbinCity_Block1", typeof(MeshRenderer), typeof(MeshFilter), typeof(MeshCollider));
            MeshFilter mf = (MeshFilter)generatedBuilding.GetComponent(typeof(MeshFilter));
            MeshRenderer mr = (MeshRenderer)generatedBuilding.GetComponent(typeof(MeshRenderer));
            MeshCollider mc = (MeshCollider)generatedBuilding.GetComponent(typeof(MeshCollider));


            Vector2[,,] footprints = GenerateBuildingFootprints(width, depth);
            List<BuildingGenerator.Building> BuildingList = new List<BuildingGenerator.Building>();
            for(int x = 0; x < footprints.GetLength(0); x++)
            {
                for(int y = 0; y < footprints.GetLength(1); y++)
                {
                    if (footprints[x, y, 0] != null && footprints[x, y, 0].x != 0)
                    {
                        
                        KerbinCity.Log("x: " + (int)footprints[x, y, 1].x +
                                                " y: " + (int)footprints[x, y, 1].y +
                                                " width: " + (int)footprints[x, y, 0].x +
                                                " depth: " + (int)footprints[x, y, 0].y);
                        BuildingList.Add(BuildingGenerator.GenerateMesh(footprints[x, y, 1].x, footprints[x, y, 1].y, footprints[x, y, 0].x, footprints[x, y, 0].y, 1.0f));
                    }
                }
            }
            
            //KerbinCity.Log(BuildingList.Count + " Buildings Generated.");

            List<Vector3> vertices = new List<Vector3>();
            List<int[]> triangles = new List<int[]>();
            List<Vector2> uv = new List<Vector2>();
            List<Material> materials = new List<Material>();

            List<Vector3> colliderVertices = new List<Vector3>();
            List<int> colliderTriangles = new List<int>();

            //KerbinCity.Log("populating temp resources...");
            foreach (BuildingGenerator.Building building in BuildingList)
            {
                int verticesOffset = vertices.Count;
                vertices.AddRange(building.Mesh.vertices);
                for(int submesh = 0; submesh < building.Mesh.subMeshCount; submesh++)
                {
                    int[] offsetTriangle = building.Mesh.GetTriangles(submesh);
                    for (int i = 0; i < offsetTriangle.Length; i++)
                    {
                        offsetTriangle[i] += verticesOffset;
                    }
                    triangles.Add(offsetTriangle);
                    materials.Add(building.Materials[submesh]);
                }
                uv.AddRange(building.Mesh.uv);

                int colliderVerticesOffset = colliderVertices.Count;
                colliderVertices.AddRange(building.ColliderMesh.vertices);
                int[] colliderOffsetTriangle = building.ColliderMesh.triangles;
                for (int i = 0; i < colliderOffsetTriangle.Length; i++)
                {
                    colliderOffsetTriangle[i] += colliderVerticesOffset;
                }
                colliderTriangles.AddRange(colliderOffsetTriangle);
            }

            Vector3[] baseVerticies = new Vector3[24]
            {
                //front
                new Vector3(0, .05f, 0), // 0
                new Vector3(width, .05f, 0),      // 1
                new Vector3(0, 0.0f, 0),    // 2
                new Vector3(width, 0.0f, 0), // 3
                //back
                new Vector3(0, .05f, depth),      // 4
                new Vector3(width, .05f, depth),       // 5
                new Vector3(0, 0.0f, depth), // 6
                new Vector3(width, 0.0f, depth),       // 7
                //right
                new Vector3(0, .05f, depth),      // 8
                new Vector3(0, .05f, 0), // 9
                new Vector3(0, 0.0f, depth), // 10
                new Vector3(0, 0.0f, 0),    // 11
                //left
                new Vector3(width, .05f, depth),       // 12
                new Vector3(width, .05f, 0),      // 13
                new Vector3(width, 0.0f, depth),       // 14
                new Vector3(width, 0.0f, 0),   // 15
                //top
                new Vector3(0, .05f, depth),      // 16
                new Vector3(width, .05f, depth),       // 17
                new Vector3(0, .05f, 0), // 18
                new Vector3(width, .05f, 0),      // 19
                //bottom
                new Vector3(width, 0.0f, 0), // 20
                new Vector3(width, 0.0f, depth),       // 21
                new Vector3(0, 0.0f, 0),    // 22
                new Vector3(0, 0.0f, depth) // 23
            };
            int verticiesOffset = vertices.Count;
            int colliderVerticiesOffset = colliderVertices.Count;
            vertices.AddRange(baseVerticies);

            Vector3[] baseColliderVertices = new Vector3[8] 
            {   
                //front
                new Vector3(0, .05f, 0), // 0
                new Vector3(width, .05f, 0),      // 1
                new Vector3(0, 0.0f, 0),    // 2
                new Vector3(width, 0.0f, 0), // 3
                //back
                new Vector3(0, .05f, depth),      // 4
                new Vector3(width, .05f, depth),       // 5
                new Vector3(0, 0.0f, depth), // 6
                new Vector3(width, 0.0f, depth),       // 7
               
            };

            colliderVertices.AddRange(baseColliderVertices);

            int[] baseTriangles = new int[36]
            {   0, 1, 2,    // front
                2, 1, 3,
                7, 5, 6,    // back
                6, 5, 4,
                8, 9, 10,    // right
                10, 9, 11,
                15, 13, 14,    // left
                14, 13, 12,
                16, 17, 18,    // top
                18, 17, 19,
                20, 21, 22,    // bottom
                22, 21, 23
             };

            for (int i = 0; i < baseTriangles.Length; i++)
            {
                baseTriangles[i] += verticiesOffset;
            }

            triangles.Add(baseTriangles);

            int[] baseColliderTriangles = new int[36]
            {   0, 1, 2,    // front
                2, 1, 3,
                7, 5, 6,    // back
                6, 5, 4,
                4, 0, 6,    // right
                6, 0, 2,
                3, 1, 7,    // left
                7, 1, 5,
                4, 5, 0,    // top
                0, 5, 1,
                3, 7, 2,    // bottom
                2, 7, 6
             };

            for (int i = 0; i < baseColliderTriangles.Length; i++)
            {
                baseColliderTriangles[i] += colliderVerticiesOffset;
            }

            colliderTriangles.AddRange(baseColliderTriangles);
            float uvwidth, uvheight, uvdepth;
            uvwidth = width / 500f;
            uvheight = .05f / 500f;
            uvdepth = depth / 500f;
            Vector2[] baseUV = new Vector2[24]
            {
                //front
                new Vector2(0,uvheight),
                new Vector2(uvwidth,uvheight),
                new Vector2(0,0),
                new Vector2(uvwidth,0),
                //back
                new Vector2(0,uvheight),
                new Vector2(uvwidth,uvheight),
                new Vector2(0,0),
                new Vector2(uvwidth,0),
                //right
                new Vector2(0,uvheight),
                new Vector2(uvdepth,uvheight),
                new Vector2(0,0),
                new Vector2(uvdepth,0),
                //left
                new Vector2(0,uvheight),
                new Vector2(uvdepth,uvheight),
                new Vector2(0,0),
                new Vector2(uvdepth,0),
                //top
                new Vector2(0,uvdepth),
                new Vector2(uvwidth,uvdepth),
                new Vector2(0,0),
                new Vector2(uvwidth,0),
                //bottom
                new Vector2(0,uvdepth),
                new Vector2(uvwidth,uvdepth),
                new Vector2(0,0),
                new Vector2(uvwidth,0)
            };

            uv.AddRange(baseUV);

            materials.Add(baseTexture);
            /*
            Vector3[] cityLightsVerticies = new Vector3[4]
            {
                new Vector3(0, 200, depth),      // 16
                new Vector3(width, 200, depth),       // 17
                new Vector3(0, 200, 0), // 18
                new Vector3(width, 200, 0)
            };
            int verticiesOffset = vertices.Count;
            vertices.AddRange(cityLightsVerticies);

            int[] cityLightsTriangles = new int[6]
            {   0, 1, 2,    // top
                2, 1, 3
             };

            for (int i = 0; i < cityLightsTriangles.Length; i++)
            {
                cityLightsTriangles[i] += verticiesOffset;
            }

            triangles.Add(cityLightsTriangles);

            Vector2[] cityLightsUV = new Vector2[4]
            {
                new Vector2(0,1),
                new Vector2(1,1),
                new Vector2(0,0),
                new Vector2(1,0)
            };

            uv.AddRange(cityLightsUV);

            materials.Add(cityLightsTexture);
            */
            //KerbinCity.Log("initializing Mesh...");
            Mesh blockMesh = new Mesh();
            blockMesh.name = "block";
            blockMesh.Clear();
            blockMesh.subMeshCount = triangles.Count;
            blockMesh.vertices = vertices.ToArray();

            //KerbinCity.Log("updating triangles...");
            for (int submesh = 0; submesh < triangles.Count; submesh++)
            {
                blockMesh.SetTriangles(triangles[submesh], submesh);
            }

            //KerbinCity.Log("setting UV...");
            blockMesh.uv = uv.ToArray();

            Mesh coliderMesh = new Mesh();
            coliderMesh.name = "blockCollider";
            coliderMesh.Clear();
            coliderMesh.subMeshCount = colliderTriangles.Count;
            coliderMesh.vertices = colliderVertices.ToArray();

            //KerbinCity.Log("updating triangles...");
            coliderMesh.triangles = colliderTriangles.ToArray();

            mf.mesh = blockMesh;
            mc.sharedMesh = coliderMesh;

            //KerbinCity.Log("setting materials...");
            for (int submesh = 0; submesh < materials.Count; submesh++)
            {
                mr.renderer.sharedMaterials = materials.ToArray();
            }

            //KerbinCity.Log("updating object...");
            blockMesh.RecalculateNormals();
            blockMesh.RecalculateBounds();

            // Set block to layer 15 so that they collide correctly with Kerbals.
            generatedBuilding.layer = 15;

            return generatedBuilding;
        }
    }
}
